Skip to content

refactor: webhook への送信と再送を Webhook::Client にまとめる - #124

Merged
limit7412 merged 2 commits into
masterfrom
claude/plan-issue-120-4urwy8
Aug 29, 2026
Merged

refactor: webhook への送信と再送を Webhook::Client にまとめる#124
limit7412 merged 2 commits into
masterfrom
claude/plan-issue-120-4urwy8

Conversation

@limit7412

Copy link
Copy Markdown
Owner

issue #123 の対応。

やったこと

Slack と Discord のアダプタは投稿の組み立て方こそ違うが、「webhook URL に JSON を POST し、一時的な失敗は再送する」点は同じで、再送の判断と待機が二重に書かれていた。
片方だけ直すと挙動がずれるため、送信そのものを Webhook::Client に切り出した。

重複していたのは次の 3 つで、すべてクライアント側に移した。

  • MAX_SEND_ATTEMPTS / MAX_RETRY_WAIT の定数
  • 429 と 5xx を Retry-After に従って再送し、それ以外は例外にする送信ループ
  • Retry-After を読んで待機上限で丸める retry_after

アダプタに残るのは投稿の組み立てと、Discord のペイロード記録(#95)だけになった。

変更点

Webhook::Client を追加した(1 コミット目)

src/webhook/client.cr に置いた。
post(body) は送信できたら戻り、恒久的に失敗したら例外にする。

送信の実体は post_json に分けてある。
ここだけを差し替えれば、HTTP を張らずに再送の判断を試せる。

Slack と Discord をクライアントに寄せた(2 コミット目)

両アダプタから再送ループと定数を取り除いた。

エラーメッセージの送信先名はクライアントに渡す service で保つため、slack webhook returned ... / discord webhook returned ... は変わらない。

spec からクライアントを差し替えられるよう、Webhook::Client を受け取る初期化を足した。
main.cr が使う URL 版の初期化はそのまま残してある。

挙動が変わる点

Slack はこれまで Content-Type を付けずに送っていたが、共通化にあわせて Discord と同じく application/json を付ける。
Slack の Incoming Webhook が案内している送り方に揃える形になる。

それ以外は変えていない。
再送の条件(429 と 5xx)、試行回数(3 回)、待機上限(5 秒)、Retry-After が無いときの既定(1 秒)はどちらも従来どおり。

テスト

crystal spec は 124 examples, 0 failures。

再送の判断は spec/webhook/client_spec.cr に移した。

  • 成功したら 1 回で戻ること
  • 429 と 5xx を再送し、成功したら戻ること
  • 429 と 5xx が続いたら試行回数まで試して例外にすること
  • 恒久的な 4xx は再送せず即例外にすること
  • Retry-After が無い応答でも待機上限を超えないこと

アダプタ側の spec は投稿の分かれ方と yield の有無だけを見る。

  • spec/slack/repository_spec.cr: 全メッセージを 1 投稿で送り累計を yield すること、失敗時は yield しないこと
  • spec/discord/repository_spec.cr: 12 件なら 2 投稿に分かれ投稿ごとに累計を yield すること、失敗した投稿では yield しないこと(新規。リファクタで壊れていないことを見るために足した)

検証環境について

前回(#122)と同じく、ネットワーク制限により Crystal 1.21.0 を用意できず Ubuntu の 1.11.2 で検証している。
crystal tool format は 1.11 と 1.21 で複数行引数の末尾カンマの扱いが違いリポジトリ全体に差分を出すため実行せず、追加・変更した 6 ファイルだけを個別に確認した。
ameba は 1.11 でビルドできないためローカル実行できていない。

Closes #123


Generated by Claude Code

claude added 2 commits August 29, 2026 07:29
Slack と Discord のアダプタは投稿の組み立て方こそ違うが、「webhook URL に JSON を
POST し、一時的な失敗は再送する」点は同じで、再送の判断と待機が二重に書かれていた
(issue #123)。片方だけ直すと挙動がずれるため、送信そのものを切り出す。

まず受け皿となる Webhook::Client を追加する。アダプタの移行は次のコミットで行う。

送信の実体を post_json に分けてあるので、HTTP を張らずに再送の判断を試せる。

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmoDC7XRgDx1AcWumgv3Uq
両アダプタから再送ループ、Retry-After の解釈、リトライ回数と待機上限の定数を
取り除き、Webhook::Client に委ねる(issue #123)。アダプタに残るのは投稿の
組み立てと、Discord のペイロード記録(issue #95)だけになる。

エラーメッセージの送信先名はクライアントに渡す service で保つため、
`slack webhook returned ...` / `discord webhook returned ...` は変わらない。

Slack はこれまで Content-Type を付けずに送っていたが、共通化にあわせて Discord と
同じく application/json を付ける。Slack の Incoming Webhook が案内している送り方に
揃える形になる。

spec ではクライアントを差し替えられるよう、Webhook::Client を受け取る初期化を
足した。アダプタ側の spec は投稿の分かれ方と yield の有無だけを見る。

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SmoDC7XRgDx1AcWumgv3Uq
@limit7412
limit7412 marked this pull request as ready for review August 29, 2026 07:34
@limit7412
limit7412 merged commit 692fbca into master Aug 29, 2026
3 checks passed
@limit7412
limit7412 deleted the claude/plan-issue-120-4urwy8 branch August 29, 2026 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Slack と Discord で重複した webhook 再送ロジックを整理する

2 participants